package com.ctbri.concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Ex22 {
	
	private volatile boolean flag = false;
	
	class Task1 implements Runnable {
		@Override
		public void run() {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			flag = true;
		}
	}
	
	class Task2 implements Runnable {
		private int spins;
		@Override
		public void run() {
			while (true) {
				while(!flag &&
						!Thread.currentThread().isInterrupted())
					spins++;
				System.out.println("Spun " + spins + " times");
				spins = 0;
				flag = false;
				if(Thread.interrupted())
					return;
			}
		}
	}
	
	class Task3 implements Runnable {
		@Override
		public void run() {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized(Ex22.this) {
				flag = true;
				Ex22.this.notifyAll();
			}
		}
	}
	
	class Task4 implements Runnable {
		@Override
		public void run() {
			synchronized(Ex22.this) {
				while(!flag && !Thread.interrupted()) {
					try {
						Ex22.this.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				if(flag) {
					flag = false;
					System.out.println("Reset the flag");
				}
			}
		}
	}

	public static void main(String[] args) throws InterruptedException {
		Ex22 ex = new Ex22();
		ExecutorService exec = Executors.newCachedThreadPool();
		exec.execute(ex.new Task1());
		exec.execute(ex.new Task2());
		TimeUnit.SECONDS.sleep(2);
		exec.shutdownNow();
		
		exec = Executors.newCachedThreadPool();
		exec.execute(ex.new Task3());
		exec.execute(ex.new Task4());
		TimeUnit.SECONDS.sleep(10);
		exec.shutdownNow();
	}
}
